package com.example.androidaudiovideodemo.activity

import android.Manifest
import android.graphics.Color
import android.media.*
import androidx.recyclerview.widget.LinearLayoutManager
import com.blankj.utilcode.util.*
import com.example.androidaudiovideodemo.AudioListAdapter
import com.example.androidaudiovideodemo.AudioListBean
import com.example.androidaudiovideodemo.R
import com.example.androidaudiovideodemo.base.BaseActivity
import com.example.androidaudiovideodemo.utils.AudioCodecUtil
import kotlinx.android.synthetic.main.activity_mediacodec_aac.*
import java.io.File
import java.io.FileInputStream
import java.lang.Exception
import kotlin.concurrent.thread

/**
 *
 * author: renbing
 *
 * date: 2022/1/27
 *
 * des:7. 学习 MediaCodec API，完成音频 AAC 硬编、硬解
 */
class MediaCodecAACActivity : BaseActivity(){

    private val mDatas = arrayListOf<AudioListBean>()
    private var mBufferSize = 0
    private var mAdapter: AudioListAdapter<AudioListBean>? = null
    private var mLastSelectedPosition = -1
    private var mAudioDirectoryPath: String? = null
    private var mAudioRecord: AudioRecord? = null
    private var mAudioTrack: AudioTrack? = null

    override fun getLayoutId() = R.layout.activity_mediacodec_aac

    override fun performInit() {
        super.performInit()

        setStatusBarColor(this,true)
    }

    override fun initData() {
        super.initData()

        task_title_view.run {
            setLeftIconColorFilter(Color.BLACK)
            setOnLeftIconClickListener {
                finish()
            }
        }

        mAudioDirectoryPath = SDCardUtils.getSDCardPathByEnvironment()+"/$packageName/audio"
        mBufferSize = AudioRecord.getMinBufferSize(44100,AudioFormat.CHANNEL_IN_STEREO,AudioFormat.ENCODING_PCM_16BIT)
        mAudioRecord = AudioRecord(MediaRecorder.AudioSource.MIC,44100, AudioFormat.CHANNEL_IN_STEREO,AudioFormat.ENCODING_PCM_16BIT,mBufferSize)

        initRecyclerView()

        PermissionUtils.permission(Manifest.permission.READ_EXTERNAL_STORAGE)
            .callback(object : PermissionUtils.SimpleCallback{
                override fun onGranted() {
                    val audioFiles = FileUtils.listFilesInDir("${SDCardUtils.getSDCardPathByEnvironment()}/$packageName/audio")
                    audioFiles.forEach {
                        if (it.name.endsWith(".wav")) return@forEach
                        val audioListBean = AudioListBean().apply {
                            name = it.name
                            size = FileUtils.getSize(it)
                            time = TimeUtils.millis2String(it.lastModified(), "yy-MM-dd HH:mm")
                        }
                        mDatas.add(audioListBean)
                    }
                    mAdapter?.notifyDataSetChanged()
                }

                override fun onDenied() {
                    ToastUtils.showShort("无法读取内存文件")
                }

            }).request()
    }

    override fun initListener() {
        super.initListener()

        //编码
        encode_btn.setOnClickListener {
            mDatas.forEach {
                if (it.isSelect){
                    val path = "${SDCardUtils.getSDCardPathByEnvironment()}/$packageName/audio"
                    val rootDir = File(path)
                    if (!rootDir.exists() || !rootDir.isDirectory){
                        ToastUtils.showShort("文件路径已损坏")
                        return@setOnClickListener
                    }
                    rootDir.listFiles()?.forEach { file ->
                        if (file.name == it.name){
                            val filePath = file.absolutePath
                            val childName = "MediaCodeC-${System.currentTimeMillis()}.aac"
                            val outFile = File(rootDir,childName)
                            AudioCodecUtil.pcm2AAC(filePath,outFile.absolutePath,{
                                ToastUtils.showShort("编码成功")
                                val bean = AudioListBean().apply {
                                    name = childName
                                    size = FileUtils.getSize(outFile)
                                    time = TimeUtils.millis2String(outFile.lastModified(), "yy-MM-dd HH:mm")
                                }
                                mDatas.add(0,bean)
                                runOnUiThread { mAdapter?.notifyItemRangeInserted(0,1) }
                            },{
                                ToastUtils.showShort("编码失败")
                            })
                        }
                    }
                }
            }
        }
        //解码
        decode_btn.setOnClickListener {
            mDatas.forEach {
                if (it.isSelect){
                    if (it.name?.endsWith("aac") == false){
                        ToastUtils.showShort("请选择aac格式的文件进行解码")
                        return@setOnClickListener
                    }
                    val path = "${SDCardUtils.getSDCardPathByEnvironment()}/$packageName/audio"
                    val rootDir = File(path)
                    if (!rootDir.exists() || !rootDir.isDirectory){
                        ToastUtils.showShort("文件路径已损坏")
                        return@setOnClickListener
                    }
                    rootDir.listFiles()?.forEach { file ->
                        if (file.name == it.name){
                            val filePath = file.absolutePath
                            val childName = "MediaCodeC-${System.currentTimeMillis()}.pcm"
                            val outFile = File(rootDir,childName)
                            AudioCodecUtil.aac2PCMAndPlay(this,filePath,outFile,{
                                ToastUtils.showShort("解码成功")
                                val bean = AudioListBean().apply {
                                    name = childName
                                    size = FileUtils.getSize(outFile)
                                    time = TimeUtils.millis2String(outFile.lastModified(), "yy-MM-dd HH:mm")
                                }
                                mDatas.add(0,bean)
                                runOnUiThread { mAdapter?.notifyItemRangeInserted(0,1) }
                            },{
                                ToastUtils.showShort("解码失败")
                            })
                        }
                    }
                }
            }
        }

    }

    private fun initRecyclerView(){
        mAdapter = AudioListAdapter(this@MediaCodecAACActivity,mDatas,{ position, data ->
            audioPlay(data)
        }){ position, data ->
            if (mLastSelectedPosition != -1){
                mDatas[mLastSelectedPosition].isSelect = false
                mAdapter?.notifyItemRangeChanged(mLastSelectedPosition,1)
            }
            mDatas[position].isSelect = true
            mAdapter?.notifyItemRangeChanged(position,1)
            mLastSelectedPosition = position
        }
        file_rv.apply {
            adapter = mAdapter
            layoutManager = LinearLayoutManager(this@MediaCodecAACActivity)
        }
    }

    /**
     * 音频播放
     */
    private fun audioPlay(data: AudioListBean) {
        val listName = data.name
        val cacheAudioDirectory =
            FileUtils.getFileByPath(mAudioDirectoryPath) ?: File(mAudioDirectoryPath ?: "")
        if (!cacheAudioDirectory.isDirectory) {
            ToastUtils.showShort("文件已损坏")
            return
        }
        val cacheFiles = cacheAudioDirectory.listFiles() ?: arrayOf()
        if (cacheFiles.isEmpty()) {
            ToastUtils.showShort("文件已损坏")
            return
        }
        cacheFiles.forEach {
            if (it.name == listName) {
                if (mAudioRecord?.state != AudioTrack.STATE_UNINITIALIZED){
                    mAudioTrack?.stop()
                    mAudioTrack?.release()
                }
                if (listName?.endsWith(".pcm") == true){
                    playByStreamMode(listName)
                }
            }
        }
    }

    /**
     * 以MODE_STREAM播放音频
     * 从音频文件实时将数据读入缓存区buffer中，有一定延时性，处理一些延时要求不高，音频文件较大的情况
     */
    private fun playByStreamMode(listName: String?) {
        mAudioTrack = AudioTrack(
            AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build(),
            AudioFormat.Builder()
                .setSampleRate(44100)
                .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                .setChannelMask(AudioFormat.CHANNEL_IN_STEREO)
                .build(),
            mBufferSize, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE
        )
        mAudioTrack?.play()

        val playFile = File(mAudioDirectoryPath ?: "", listName ?: "")
        val fis: FileInputStream?
        try {
            fis = FileInputStream(playFile)
            thread {
                try {
                    val tmpBuffer = ByteArray(mBufferSize)
                    while (fis.available() > 0) {
                        val readCount = fis.read(tmpBuffer)
                        if (readCount == AudioTrack.ERROR_INVALID_OPERATION || readCount == AudioTrack.ERROR_BAD_VALUE) continue
                        if (readCount > 0) {
                            mAudioTrack?.write(tmpBuffer, 0, readCount)
                        }
                    }
                    fis.close()
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun onPause() {
        super.onPause()

        mAudioRecord?.release()
        mAudioRecord = null
        mAudioTrack?.release()
        mAudioTrack = null
    }
}